package com.ly.mp.busicen.rule.flow.action;

import static com.ly.mp.busicen.rule.XruleStrUtils.splitJKH;
import static com.ly.mp.busicen.rule.XruleStrUtils.splitZKH;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Map;

import org.springframework.cglib.core.SpringNamingPolicy;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.util.StringUtils;

import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.ly.mp.busicen.rule.flow.DynamicTypeLib;
import com.ly.mp.busicen.rule.flow.FlowUserMode;

import reactor.core.publisher.Flux;

public abstract class ActionExecuteBase implements IActionExecute {

	static Extention __extention = new Extention();

	/**
	 * 下一个节点
	 * 
	 * @param action
	 * @param nextActionLable
	 * @return
	 */
	public String nextActionCode(IAction action, String nextActionLable) {
		String nextStr = action.nextAction();
		Map<String, String> actions = Flux.fromArray(nextStr.split(";")).collectMap(m -> splitJKH(m), m -> splitZKH(m))
				.block();
		if (actions.size() == 0) {
			String error = String.format("未配置节点出口", nextActionLable);
			throw new ActionException(error);
		}

		String nextAction = actions.get(nextActionLable);
		if (StringUtils.isEmpty(nextAction)) {
			String error = String.format("节点返回【%s】编号未配置出口", nextActionLable);
			throw new ActionException(error);
		}

		return nextAction;
	}

	/**
	 * 下一个节点
	 * 
	 * @param action
	 * @param nextActionLable
	 * @return
	 */
	public String defaultNextActionCode(IAction action, String nextActionLable) {
		return defaultNextAction(action, nextActionLable);
	}

	public static String defaultNextAction(IAction action, String nextActionLable) {
		String nextStr = action.nextAction();
		Map<String, String> actions = Flux.fromArray(nextStr.split(";")).collectMap(m -> splitJKH(m), m -> splitZKH(m))
				.block();
		if (actions.size() == 0) {
			String error = String.format("未配置节点出口", nextActionLable);
			throw new ActionException(error);
		}
		String nextAction = actions.get(nextActionLable);
		if (StringUtils.isEmpty(nextAction)) {
			nextAction = actions.get(null);
			if (StringUtils.isEmpty(nextAction)) {
				nextAction = String.valueOf(actions.values().toArray()[0]);
			}
		}

		return nextAction;
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	private static Map wrapperMap(Map data) {
		data.put("__user", FlowUserMode.currentUser());
		data.put("__extention", __extention);
		return data;
	}

	public static class Extention implements Serializable {
		private static final long serialVersionUID = 1L;

		public String getUuid() {
			return IdWorker.get32UUID();
		}
	}

	private static Object wrapperObj(Object object) {
		Enhancer enhancer = new Enhancer();
		enhancer.setSuperclass(object.getClass());
		enhancer.setInterfaces(new Class[] { DynamicTypeLib.USER_WRAP_INTERFACE });
		enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
		enhancer.setCallback(new MethodInterceptor() {
			@Override
			public Object intercept(Object obj, Method method, Object[] param, MethodProxy px) throws Throwable {
				if (method.getName().equals("get__user")) {
					return FlowUserMode.currentUser();
				}
				if (method.getName().equals("get__extention")) {
					return __extention;
				}
				Object result = method.invoke(object, param);
				return result;
			}
		});
		return enhancer.create();
	}

	/**
	 * 将数据包装用户信息
	 * 
	 * @param data
	 * @return data
	 */
	public static Object wrapperUserData(Object data) {
		if (data == null) {
			return null;
		}
		if(data instanceof Iterable) {
			Iterable<?> listData = (Iterable<?>) data;
			for (Object object : listData) {
				wrapperUserDataPer(object);
			}
			return data;
		}else {
			return wrapperUserDataPer(data);
		}
	}
	@SuppressWarnings("rawtypes")
	public static Object wrapperUserDataPer(Object data) {
		if (data == null) {
			return null;
		}

		if (data instanceof Map) {
			return wrapperMap((Map) data);
		} else {
			if (!Modifier.isFinal(data.getClass().getModifiers())) {
				return wrapperObj(data);
			} else {
				return data;
			}
		}
	}

}
